﻿using System;
using System.Buffers;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

namespace WholeSlideImageLibrary
{
    internal class PhysicalFileReader : FileSourceReader
    {
        private Stream? _stream;

        public PhysicalFileReader(string fileName)
        {
            _stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true);
        }

        public override async ValueTask<int> ReadAsync(long offset, Memory<byte> buffer, CancellationToken cancellationToken)
        {
            Stream? stream = _stream;
            if (stream is null)
            {
                throw new ObjectDisposedException(nameof(PhysicalFileReader));
            }

            stream.Seek(offset, SeekOrigin.Begin);
#if NO_FAST_SPAN
            if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> segment))
            {
                return await stream.ReadAsync(segment.Array, segment.Offset, segment.Count, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                byte[] arrayBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
                try
                {
                    int bytesRead = await stream.ReadAsync(arrayBuffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
                    arrayBuffer.AsSpan(0, bytesRead).CopyTo(buffer.Span);
                    return bytesRead;
                }
                finally
                {
                    ArrayPool<byte>.Shared.Return(arrayBuffer);
                }
            }
#else
            return await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
#endif
        }

        public override ValueTask DisposeAsync()
        {
            if (!(_stream is null))
            {
                _stream.Dispose();
                _stream = null;
            }
            return base.DisposeAsync();
        }
    }
}
